package api

import (
	"django_blog_gin/internal/dto"
	"django_blog_gin/internal/model"
	"django_blog_gin/internal/repository"
	"django_blog_gin/internal/svc"
	"django_blog_gin/internal/utils"
	"fmt"
	"io"
	"net/http"
	"path/filepath"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

type BlogArticleController struct {
	svcCtx *svc.ServiceContext
}

func NewBlogArticleController(svcCtx *svc.ServiceContext) *BlogArticleController {
	return &BlogArticleController{svcCtx: svcCtx}
}

func (ctr BlogArticleController) GetArticleList(c *gin.Context) {
	limit := c.DefaultQuery("limit", "10")
	offset := c.DefaultQuery("offset", "0")
	repo := repository.NewArticle(ctr.svcCtx)
	articleList, err := repo.GetArticleList(limit, offset)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}

	type ArticleResp struct {
		model.BlogArticle
		CreatedTime string `json:"created_time"`
		LastModTime string `json:"last_mod_time"`
		PubTime     string `json:"pub_time"`
	}
	respList := make([]ArticleResp, 0, len(articleList))
	for _, a := range articleList {
		respList = append(respList, ArticleResp{
			BlogArticle: a,
			CreatedTime: a.CreatedTime.Format("2006-01-02 15:04:05"),
			LastModTime: a.LastModTime.Format("2006-01-02 15:04:05"),
			PubTime:     a.PubTime.Format("2006-01-02 15:04:05"),
		})

	}

	utils.ResponseSuccess(c, respList, "ok")
}

func (ctr BlogArticleController) GetArticleWithTagsList(c *gin.Context) {
	limit := c.DefaultQuery("limit", "10")
	offset := c.DefaultQuery("offset", "0")
	order := c.DefaultQuery("order", "article_order")     // 大的在前面
	orderPrefix := c.DefaultQuery("order_prefix", "DESC") // DESC
	category := c.DefaultQuery("category", "")
	repo := repository.NewArticle(ctr.svcCtx)
	articleList, err := repo.GetArticleWithTagsList(limit, offset, order, orderPrefix, category)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}

	// type ArticleResp struct {
	// 	model.BlogArticleWithTags
	// 	CreatedTime string   `json:"created_time"`
	// 	LastModTime string   `json:"last_mod_time"`
	// 	PubTime     string   `json:"pub_time"`
	// 	Tags        []string `json:"tags"`
	// }
	respList := make([]dto.ArticleWithTagsResp, 0, len(articleList))
	for _, a := range articleList {
		respList = append(respList, dto.ArticleWithTagsResp{
			BlogArticleWithTags: a,
			CreatedTime:         a.CreatedTime.Format("2006-01-02 15:04:05"),
			LastModTime:         a.LastModTime.Format("2006-01-02 15:04:05"),
			PubTime:             a.PubTime.Format("2006-01-02 15:04:05"),
			Tags:                strings.Split(a.Tags, ","),
		})
	}

	utils.ResponseSuccess(c, respList, "ok")
}

// 获取隐私的文章
func (ctr BlogArticleController) GetArticleWithTagsListForPrivate(c *gin.Context) {
	limit := c.DefaultQuery("limit", "10")
	offset := c.DefaultQuery("offset", "0")
	order := c.DefaultQuery("order", "article_order")     // 大的在前面
	orderPrefix := c.DefaultQuery("order_prefix", "DESC") // DESC
	repo := repository.NewArticle(ctr.svcCtx)
	articleList, err := repo.GetArticleWithTagsListForPrivate(limit, offset, order, orderPrefix)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}

	type ArticleResp struct {
		model.BlogArticleWithTags
		CreatedTime string   `json:"created_time"`
		LastModTime string   `json:"last_mod_time"`
		PubTime     string   `json:"pub_time"`
		Tags        []string `json:"tags"`
	}
	respList := make([]ArticleResp, 0, len(articleList))
	for _, a := range articleList {
		respList = append(respList, ArticleResp{
			BlogArticleWithTags: a,
			CreatedTime:         a.CreatedTime.Format("2006-01-02 15:04:05"),
			LastModTime:         a.LastModTime.Format("2006-01-02 15:04:05"),
			PubTime:             a.PubTime.Format("2006-01-02 15:04:05"),
			Tags:                strings.Split(a.Tags, ","),
		})
	}

	utils.ResponseSuccess(c, respList, "ok")
}

func (ctr BlogArticleController) GetArticleDetail(c *gin.Context) {
	var req dto.GetArticleDetailReq

	if !utils.ValidateJsonBody(c, &req) {
		return
	}
	repo := repository.NewArticle(ctr.svcCtx)
	articleDetail, err := repo.GetArticleDetail(req.Id)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}

	type ArticleResp struct {
		model.BlogArticleDetail
		CreatedTime string   `json:"created_time"`
		LastModTime string   `json:"last_mod_time"`
		PubTime     string   `json:"pub_time"`
		Tags        []string `json:"tags"`
	}

	utils.ResponseSuccess(c, ArticleResp{
		BlogArticleDetail: articleDetail,
		CreatedTime:       articleDetail.CreatedTime.Format("2006-01-02 15:04:05"),
		LastModTime:       articleDetail.LastModTime.Format("2006-01-02 15:04:05"),
		PubTime:           articleDetail.PubTime.Format("2006-01-02 15:04:05"),
		Tags:              strings.Split(articleDetail.Tags, ","),
	}, "ok")
}

func (ctr BlogArticleController) GetArticleWithTagDetail(c *gin.Context) {
	var req dto.GetArticleDetailReq

	if !utils.ValidateJsonBody(c, &req) {
		return
	}
	repo := repository.NewArticle(ctr.svcCtx)
	articleDetail, err := repo.GetArticleWithTagDetail(req.Id)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}

	type ArticleResp struct {
		model.BlogArticleWithTagDetail
		CreatedTime string `json:"created_time"`
		LastModTime string `json:"last_mod_time"`
		PubTime     string `json:"pub_time"`
	}

	utils.ResponseSuccess(c, ArticleResp{
		BlogArticleWithTagDetail: articleDetail,
		CreatedTime:              articleDetail.CreatedTime.Format("2006-01-02 15:04:05"),
		LastModTime:              articleDetail.LastModTime.Format("2006-01-02 15:04:05"),
		PubTime:                  articleDetail.PubTime.Format("2006-01-02 15:04:05"),
	}, "ok")
}

func (ctr BlogArticleController) GetBlogSettingsList(c *gin.Context) {
	blogSettings := model.BlogSettings{}
	err := ctr.svcCtx.MysqlDb.Get(&blogSettings, "select * from blog_settings")
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code":    500,
			"message": "获取博客设置失败",
		})
		return
	}
}

// 读取.md文件导入到blog生成文章, 标题为前五个字符
func (ctr BlogArticleController) ImportMdField(c *gin.Context) {

	rFile, err := c.FormFile("file")
	if err != nil {
		c.String(400, "文件格式错误")
		return
	}

	if rFile.Size > 5000000 {
		c.String(400, "文件大小超过2M")
		return
	}

	ext := filepath.Ext(rFile.Filename)
	if ext != ".md" {
		c.JSON(400, "Only .md files are allowed")
		return
	}

	file, err := rFile.Open()
	if err != nil {
		c.String(400, "文件格式错误.必须要是.md格式的文件")
		return
	}
	defer file.Close()

	// 读取csv
	// reader := csv.NewReader(bufio.NewReader(file))
	// for {
	// 	line, err := reader.Read()
	// 	if err != nil {
	// 		c.String(400, err.Error())
	// 		return
	// 	}
	// 	//line 就是每一行的内容
	// 	fmt.Println(line)
	// 	//line[0] 就是第几列
	// 	fmt.Println(line[0])
	// }

	// 读取.md文档
	content, err := io.ReadAll(file)
	if err != nil {
		c.String(500, "文件读取错误")
		return
	}
	contentStr := string(content)
	// 输出文件的内容
	// fmt.Println(contentStr)

	now := time.Now()
	nowStr := now.Format(time.RFC3339)

	article := model.BlogArticle{
		CreatedTime:   now,
		LastModTime:   now,
		Title:         ctr.getTitle(contentStr, nowStr),
		Body:          contentStr,
		PubTime:       now,
		Status:        model.StatusPublished,
		CommentStatus: model.CommentClose,
		Type:          model.TypeArticle,
		Views:         0,
		ArticleOrder:  0,
		ShowToc:       false,
		AuthorId:      1,
		CategoryId:    1,
	}
	sql := fmt.Sprintf("INSERT INTO %s (created_time, last_mod_time, title, body, pub_time, status, comment_status, type, views, article_order, show_toc, author_id, category_id) VALUES (:created_time,:last_mod_time,:title,:body,:pub_time,:status,:comment_status,:type,:views,:article_order,:show_toc,:author_id,:category_id)", article.TableName())
	_, err = ctr.svcCtx.MysqlDb.NamedExec(sql, article)
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	// 返回成功的响应
	c.String(200, "ok")
}

// 自动获取标题:
// 以当前时间为开头: 获取第一行作为标题 ? 如果没有第一行就截取前5个字符
func (ctr BlogArticleController) getTitle(content string, nowStr string) string {
	var title string
	title = nowStr
	contentSplits := strings.Split(content, "\n")
	if len(contentSplits) == 0 {
		title += content[:min(len(content), 5)]
	} else {
		title += contentSplits[0]
	}
	return title
}

func (ctr BlogArticleController) UpdateBlogArticle(c *gin.Context) {
	var req dto.UpdateBlogArticleReq
	if !utils.ValidateJsonBody(c, &req) {
		return
	}

	repo := repository.NewArticle(ctr.svcCtx)

	// 修改article
	err := repo.UpdateArticle(req)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}

	// 修改tags
	err = repo.UpdateArticleTags(req.Id, req.TagIds)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}

	//同步到es
	esRepo := repository.NewEsArticleRepo(ctr.svcCtx)
	err = esRepo.SyncArticleToES(req.Id)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}

	utils.ResponseSuccess(c, "", "ok")
}

func (ctr BlogArticleController) UpdateBlogSettings(c *gin.Context) {
	// var blogSettingsList models.BlogSettings
	var req dto.UpdateBlogSettingsListReq
	if !utils.ValidateJsonBody(c, &req) {
		return
	}
	m := model.BlogSettings{}
	sql := fmt.Sprintf("UPDATE %s SET ", m.TableName())

	_, err := ctr.svcCtx.MysqlDb.NamedExec(sql+
		"sitename:=sitename"+
		"site_description:=site_description"+
		"site_seo_description:=site_seo_description"+
		"site_keywords:=site_keywords"+
		"article_sub_length:=article_sub_length"+
		"sidebar_comment_count:=sidebar_comment_count"+
		"sidebar_article_count:=sidebar_article_count"+
		"article_comment_count:=article_comment_count"+
		"show_google_adsense:=show_google_adsense"+
		"google_adsense_codes:=google_adsense_codes"+
		"open_site_comment:=open_site_comment"+
		"beiancode:=beiancode"+
		"analyticscode:=analyticscode"+
		"show_gongan_code:=show_gongan_code"+
		"gongan_beiancode:=gongan_beiancode", req)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
}

func (ctr BlogArticleController) CreateArticle(c *gin.Context) {
	var req dto.CreateBlogArticleReq
	if !utils.ValidateJsonBody(c, &req) {
		return
	}

	repo := repository.NewArticle(ctr.svcCtx)
	err := repo.CreateArticle(&req)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}

	utils.ResponseSuccess(c, "", "ok")
}

func (ctr BlogArticleController) GetHotArticle(c *gin.Context) {
	repo := repository.NewArticle(ctr.svcCtx)
	articleList, err := repo.GetHotArticle()
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}
	utils.ResponseSuccess(c, articleList, "ok")
}

func (ctr BlogArticleController) GetMyArticleList(c *gin.Context) {
	limit := c.DefaultQuery("limit", "10")
	offset := c.DefaultQuery("offset", "0")

	tokenData, _ := c.Get("tokenData")
	authorID := tokenData.(utils.TokenMap).UserId

	repo := repository.NewArticle(ctr.svcCtx)
	articleList, err := repo.GetMyArticleList(authorID, limit, offset)
	if err != nil {
		utils.ResponseError(c, 400, err.Error())
		return
	}
	utils.ResponseSuccess(c, articleList, "ok")
}
